# clean_region.py
import sys
from utils import load_csv, save_df, logger
import pandas as pd
import os
import ast  # 更安全地解析字符串为列表
from utils import validate_numeric_range

# 获取当前脚本的目录（data_cleaning），然后获取其父目录（项目根目录）
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 将项目根目录添加到sys.path
if project_root not in sys.path:
    sys.path.insert(0, project_root)
from config import PATH_REGION, OUT_REGION

# 确保输出目录存在
os.makedirs(os.path.dirname(OUT_REGION), exist_ok=True)

def clean_region_topology():
    logger.info("开始清洗 region_topology.csv ...")

    # 原始数据加载
    df = load_csv(PATH_REGION, "区域拓扑数据")
    if df is None or df.empty:
        logger.error("加载的区域拓扑数据为空或加载失败，终止清洗。")
        return None

    # 阶段 1: 缺失值处理
    logger.info("阶段 1: 处理缺失值...")
    df['parent_region'] = df['parent_region'].fillna('CN_GZ')
    df['adjacent_regions'] = df['adjacent_regions'].fillna('[]')
    save_df(df, OUT_REGION.replace('.csv', '_stage1.csv'), "缺失值处理后")

    # 阶段 2: 数据类型标准化（字符串转列表，region_id 转字符串）
    logger.info("阶段 2: 数据类型标准化...")
    df['region_id'] = df['region_id'].astype(str)

    # 使用 ast.literal_eval 替代 eval，更安全
    def safe_eval_list(x):
        try:
            result = ast.literal_eval(x) if isinstance(x, str) else x
            return result if isinstance(result, list) else []
        except Exception:
            logger.warning(f"无法解析 adjacent_regions: {x}，使用空列表替代")
            return []

    df['adjacent_regions'] = df['adjacent_regions'].apply(safe_eval_list)
    save_df(df, OUT_REGION.replace('.csv', '_stage2.csv'), "类型标准化后")

    # 阶段 3: 数值字段校验（带宽 > 0）
    logger.info("阶段 3: 带宽字段合理性校验...")
    mask = validate_numeric_range(df['bandwidth_capacity'], min_val=0.1, field_name='bandwidth_capacity')
    invalid_bandwidth_count = (~mask).sum()
    if invalid_bandwidth_count > 0:
        logger.warning(f"发现 {invalid_bandwidth_count} 条带宽异常记录（≤0.1），已过滤")
    df = df[mask].copy()
    save_df(df, OUT_REGION.replace('.csv', '_stage3.csv'), "带宽校验后")

    # 阶段 4: 逻辑一致性校验（backup_region_id 必须是合法 region_id）
    logger.info("阶段 4: 备份区域合法性校验...")
    valid_region_ids = set(df['region_id'])  # 当前有效的 region_id 集合

    def is_backup_valid(backup_id):
        if pd.isna(backup_id):
            return True
        return str(backup_id) in valid_region_ids

    df['backup_region_valid'] = df['backup_region_id'].apply(is_backup_valid)
    invalid_backup_count = (~df['backup_region_valid']).sum()
    if invalid_backup_count > 0:
        logger.warning(f"发现 {invalid_backup_count} 条无效 backup_region_id，已过滤")
    df = df[df['backup_region_valid']].copy()
    df.drop(columns=['backup_region_valid'], inplace=True, errors='ignore')  # 清理临时列
    save_df(df, OUT_REGION.replace('.csv', '_stage4.csv'), "备份区域校验后")

    # 阶段 5: 去重（按 region_id）
    logger.info("阶段 5: 去重处理...")
    duplicate_count = df.duplicated(subset=['region_id']).sum()
    if duplicate_count > 0:
        logger.warning(f"发现 {duplicate_count} 条重复 region_id，保留第一条")
    df.drop_duplicates(subset=['region_id'], keep='first', inplace=True)
    save_df(df, OUT_REGION.replace('.csv', '_stage5.csv'), "去重后")

    # 最终输出
    save_df(df, OUT_REGION, "清洗后的区域拓扑")
    logger.info(f"region_topology 清洗完成，最终保留 {len(df)} 条有效记录。")
    logger.info(f"所有中间阶段结果已保存至 {os.path.dirname(OUT_REGION)} 目录。")

    return df  # 返回清洗后的 DataFrame，供其他模块引用


if __name__ == "__main__":
    clean_region_topology()